home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Ham Radio 2000
/
Ham Radio 2000.iso
/
ham2000
/
tcp_ip
/
jnos
/
jnos_src
/
smtpcli.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-08-26
|
32KB
|
1,194 lines
/*
* CLIENT routines for Simple Mail Transfer Protocol ala RFC821
* A.D. Barksdale Garbee II, aka Bdale, N3EUA
* Copyright 1986 Bdale Garbee, All Rights Reserved.
* Permission granted for non-commercial copying and use, provided
* this notice is retained.
* Modified 14 June 1987 by P. Karn for symbolic target addresses,
* also rebuilt locking mechanism
* Copyright 1987 1988 David Trulli, All Rights Reserved.
* Permission granted for non-commercial copying and use, provided
* this notice is retained.
*/
/* Mods by G1EMM and PA0GRI */
#include <fcntl.h>
#include <time.h>
#include <setjmp.h>
#ifdef UNIX
#include <sys/types.h>
#endif
#ifdef AMIGA
#include <stat.h>
#else
#include <sys/stat.h>
#endif
#ifdef __TURBOC__
#include <dir.h>
#include <io.h>
#endif
#include "global.h"
#ifdef ANSIPROTO
#include <stdarg.h>
#endif
#include "mbuf.h"
#include "cmdparse.h"
#include "proc.h"
#include "socket.h"
#ifdef LZW
#include "lzw.h"
#endif
#include "timer.h"
#include "netuser.h"
#include "smtp.h"
#include "dirutil.h"
#include "commands.h"
#include "session.h"
#include "files.h"
#ifdef HOPPER
#include "ip.h"
int UseHopper = 1; /* G8FSL SMTP hopper default ON */
static int dohopper __ARGS((int argc,char *argv[],void *p)); /* g8fsl */
#endif
struct timer Smtpcli_t; /* not static because referenced in dosend() */
static int32 Gateway;
static int smtp_running=0;
#ifdef SMTPTRACE
unsigned short Smtptrace = 0; /* used for trace level */
static int dosmtptrace __ARGS((int argc,char *argv[],void *p));
static char smtp_recv[] = "smtpcli recv: %s\n";
#endif
static unsigned short Smtpmaxcli = MAXSESSIONS; /* the max client connections allowed */
static int Smtpsessions = 0; /* number of client connections
* currently open */
#ifdef LZW
int Smtpslzw = 1;
int Smtpclzw = 1;
static int Smtpbatch = 1;
#else
static int Smtpbatch = 0;
#endif
int Smtpmode = 0;
int SmtpBidCheck = 1;
int Smtpquiet = 0;
int UseMX = 0; /* use MX records in domain lookup */
static struct smtpcli *cli_session[MAXSESSIONS]; /* queue of client sessions */
static void smtp_fwd __ARGS((int unused,void *t,void *p));
static void del_job __ARGS((struct smtp_job *jp));
static void del_session __ARGS((struct smtpcli *cb));
static int dogateway __ARGS((int argc,char *argv[],void *p));
static int dosmtpmaxcli __ARGS((int argc,char *argv[],void *p));
static int dotimer __ARGS((int argc,char *argv[],void *p));
static int doquiet __ARGS((int argc,char *argv[],void *p));
static int doclzw __ARGS((int argc,char *argv[],void *p));
static int doslzw __ARGS((int argc,char *argv[],void *p));
static int dousemx __ARGS((int argc,char *argv[],void *p));
static int dosmtpkill __ARGS((int argc,char *argv[],void *p));
static int dosmtplist __ARGS((int argc,char *argv[],void *p));
static int dobatch __ARGS((int argc,char *argv[],void *p));
static void execjobs __ARGS((void));
static int getresp __ARGS((struct smtpcli *ftp,int mincode));
static void logerr __ARGS((struct smtpcli *cb,char *line));
static struct smtpcli *lookup __ARGS((int32 destaddr));
static struct smtpcli *newcb __ARGS((void));
static int next_job __ARGS((struct smtpcli *cb));
static void retmail __ARGS((struct smtpcli *cb));
static void sendcmd __ARGS((struct smtpcli *cb,char *fmt,...));
static int smtpsendfile __ARGS((struct smtpcli *cb));
static int setsmtpmode __ARGS((int argc,char *argv[],void *p));
static struct smtp_job *setupjob __ARGS((struct smtpcli *cb,char *id,char *from));
static void smtp_send __ARGS((int unused,void *cb1,void *p));
static int smtpkick __ARGS((int argc,char *argv[],void *p));
static int dosmtpt4 __ARGS((int argc,char *argv[],void *p));
static int dosmtpservtdisc __ARGS((int argc,char *argv[],void *p));
static int dobidcheck __ARGS((int argc,char *argv[],void *p));
static struct cmds Smtpcmds[] = {
"batch", dobatch, 0, 0, NULLCHAR,
"bidcheck", dobidcheck, 0, 0, NULLCHAR,
"gateway", dogateway, 0, 0, NULLCHAR,
#ifdef HOPPER
"hopper", dohopper, 0, 0, NULLCHAR, /* g8fsl */
#endif
"kick", smtpkick, 0, 0, NULLCHAR,
"kill", dosmtpkill, 0, 2, "kill <jobnumber>",
"list", dosmtplist, 0, 0, NULLCHAR,
"maxclients", dosmtpmaxcli, 0, 0, NULLCHAR,
"mode", setsmtpmode, 0, 0, NULLCHAR,
"quiet", doquiet, 0, 0, NULLCHAR,
#ifdef LZW
"reclzw", doslzw, 0, 0, NULLCHAR,
"sendlzw", doclzw, 0, 0, NULLCHAR,
#endif
"tdisc", dosmtpservtdisc,0,0,NULLCHAR,
"timer", dotimer, 0, 0, NULLCHAR,
#ifdef SMTPTRACE
"trace", dosmtptrace, 0, 0, NULLCHAR,
#endif
"t4", dosmtpt4, 0, 0, NULLCHAR,
"usemx", dousemx, 0, 0, NULLCHAR,
NULLCHAR,
};
int
dosmtp(argc,argv,p)
int argc;
char *argv[];
void *p;
{
return subcmd(Smtpcmds,argc,argv,p);
}
int Smtpt4;
static int
dosmtpt4(argc,argv,p)
int argc;
char *argv[];
void *p;
{
return setint(&Smtpt4,"SMTP T4",argc,argv);
}
int SmtpServTdisc;
static int
dosmtpservtdisc(argc,argv,p)
int argc;
char *argv[];
void *p;
{
return setint(&SmtpServTdisc,"Server tdisc (sec)",argc,argv);
}
static int
dobatch(argc,argv,p)
int argc;
char *argv[];
void *p;
{
return setbool(&Smtpbatch,"SMTP batching",argc,argv);
}
static int
dobidcheck(argc,argv,p)
int argc;
char *argv[];
void *p;
{
return setbool(&SmtpBidCheck,"SMTP BID Checking",argc,argv);
}
#ifdef LZW
static int
doclzw(argc,argv,p)
int argc;
char *argv[];
void *p;
{
return setbool(&Smtpclzw,"SMTP send lzw",argc,argv);
}
#endif
static int
doquiet(argc,argv,p)
int argc;
char *argv[];
void *p;
{
return setbool(&Smtpquiet,"SMTP quiet",argc,argv);
}
#ifdef LZW
static int
doslzw(argc,argv,p)
int argc;
char *argv[];
void *p;
{
return setbool(&Smtpslzw,"SMTP recv lzw",argc,argv);
}
#endif
static int
dousemx(argc,argv,p)
int argc;
char *argv[];
void *p;
{
return setbool(&UseMX,"MX records used",argc,argv);
}
static int
dosmtpmaxcli(argc,argv,p)
int argc;
char *argv[];
void *p;
{
return setshort(&Smtpmaxcli,"Max clients",argc,argv);
}
static int
setsmtpmode(argc,argv,p)
int argc;
char *argv[];
void *p;
{
if (argc < 2) {
tprintf("smtp mode: %s\n",
(Smtpmode & QUEUE) ? "queue" : "route");
} else {
switch(*argv[1]) {
case 'q':
Smtpmode |= QUEUE;
break;
case 'r':
Smtpmode &= ~QUEUE;
break;
default:
tputs("Usage: smtp mode [queue | route]\n");
break;
}
}
return 0;
}
static int
dogateway(argc,argv,p)
int argc;
char *argv[];
void *p;
{
int32 n;
if(argc < 2){
tprintf("%s\n",inet_ntoa(Gateway));
} else if((n = resolve(argv[1])) == 0){
tprintf(Badhost,argv[1]);
return 1;
} else
Gateway = n;
return 0;
}
#ifdef HOPPER
static int
dohopper(argc,argv,p)
int argc;
char *argv[];
void *p;
{
return setbool(&UseHopper,"G8FSL mail hopper",argc,argv);
}
#endif
#ifdef SMTPTRACE
static int
dosmtptrace(argc,argv,p)
int argc;
char *argv[];
void *p;
{
return setshort(&Smtptrace,"SMTP tracing",argc,argv);
}
#endif
/* list jobs waiting to be sent in the mqueue */
static int
dosmtplist(argc,argv,p)
int argc;
char *argv[];
void *p;
{
char tstring[80];
char line[20];
char host[LINELEN];
char to[LINELEN];
char from[LINELEN];
char *cp;
char status;
int flowsave;
struct ffblk ff;
struct ftime *ft;
FILE *fp;
flowsave = Current->flowmode;
Current->flowmode = 1; /* Enable the more mechanism */
tputs("S Job Size Date Time Host From\n");
filedir(Mailqueue,0,line);
while(line[0] != '\0') {
sprintf(tstring,"%s/%s",Mailqdir,line);
if ((fp = fopen(tstring,READ_TEXT)) == NULLFILE) {
tprintf("Can't open %s: %s\n",tstring,sys_errlist[errno]);
continue;
}
if ((cp = strrchr(line,'.')) != NULLCHAR)
*cp = '\0';
sprintf(tstring,"%s/%s.lck",Mailqdir,line);
if (access(tstring,0))
status = ' ';
else
status = 'L';
/* This is a no-no for Borland compilers...
* Blows up DV and OS/2 VDM !
* stat(tstring,&stbuf);
*/
sprintf(tstring,"%s/%s.txt",Mailqdir,line);
findfirst(tstring,&ff,0);
ft = (struct ftime *) &ff.ff_ftime;
fgets(host,sizeof(host),fp);
rip(host);
fgets(from,sizeof(from),fp);
rip(from);
tprintf("%c %5s %6ld %02d/%02d %02d:%02d %-20s %s\n To:",
status, line,
ff.ff_fsize,
ft->ft_month,ft->ft_day,
ft->ft_hour,ft->ft_min,
host,from);
while (fgets(to,sizeof(to),fp) != NULLCHAR) {
rip(to);
tprintf(" %s",to);
}
tputc('\n');
(void) fclose(fp);
pwait(NULL);
filedir(Mailqueue,1,line);
}
Current->flowmode = flowsave;
return 0;
}
/* kill a job in the mqueue */
static int
dosmtpkill(argc,argv,p)
int argc;
char *argv[];
void *p;
{
char s[SLINELEN];
char *cp,c;
sprintf(s,"%s/%s.lck",Mailqdir,argv[1]);
cp = strrchr(s,'.');
if (!access(s,0)) {
Current->ttystate.echo = Current->ttystate.edit = 0;
c = keywait("Warning, job is locked by SMTP. Remove (y/n)? ",0);
Current->ttystate.echo = Current->ttystate.edit = 1;
if (c != 'y')
return 0;
(void) unlink(s);
}
strcpy(cp,".wrk");
if (unlink(s))
tprintf("Job id %s not found\n",argv[1]);
strcpy(cp,".txt");
(void) unlink(s);
return 0;
}
/* Set outbound spool scan interval */
static int
dotimer(argc,argv,p)
int argc;
char *argv[];
void *p;
{
if(argc < 2){
tprintf("smtp timer = %lu/%lu\n",
read_timer(&Smtpcli_t)/1000L,
dur_timer(&Smtpcli_t)/1000L);
return 0;
}
Smtpcli_t.func = (void (*)__ARGS((void*)))smtptick;/* what to call on timeout */
Smtpcli_t.arg = NULL; /* dummy value */
set_timer(&Smtpcli_t,atol(argv[1])*1000L); /* set timer duration */
start_timer(&Smtpcli_t); /* and fire it up */
return 0;
}
static int
smtpkick(argc,argv,p)
int argc;
char *argv[];
void *p;
{
int32 addr = 0;
if(argc > 1 && (addr = resolve(argv[1])) == 0){
tprintf(Badhost,argv[1]);
return 1;
}
smtptick((void *)addr);
return 0;
}
/* This is the routine that gets called every so often to do outgoing
* mail processing. When called with a null argument, it runs the entire
* queue; if called with a specific non-zero IP address from the remote
* kick server, it only starts up sessions to that address.
*/
void
smtptick(t)
void *t;
{
if (!smtp_running) {
smtp_running=1;
if(newproc("smtp_fwd", 2048, smtp_fwd, 0, t,NULL,0) == NULLPROC) {
start_timer(&Smtpcli_t);
smtp_running = 0;
}
}
}
/* The old smtptick function now becomes a process "smtp_fwd"
*/
static void
smtp_fwd(unused,t,p)
int unused;
void *t;
void *p;
{
register struct smtpcli *cb;
struct smtp_job *jp;
struct list *ap;
char tmpstring[LINELEN], wfilename[13], prefix[9];
char from[LINELEN], to[LINELEN];
char *cp, *cp1;
int32 destaddr,target;
FILE *wfile;
target = (int32)t;
#ifdef SMTPTRACE
if (Smtptrace > 5)
printf("smtp daemon entered, target = %s\n",inet_ntoa(target));
#endif
if(availmem() < Memthresh){
/* Memory is tight, don't do anything */
/* Restart timer */
start_timer(&Smtpcli_t);
smtp_running = 0;
return;
}
for(filedir(Mailqueue,0,wfilename);wfilename[0] != '\0';
filedir(Mailqueue,1,wfilename)){
/* save the prefix of the file name which it job id */
cp = wfilename;
cp1 = prefix;
while (*cp && *cp != '.')
*cp1++ = *cp++;
*cp1 = '\0';
/* lock this file from the smtp daemon */
if (mlock(Mailqdir,prefix))
continue;
sprintf(tmpstring,"%s/%s",Mailqdir,wfilename);
if ((wfile = fopen(tmpstring,READ_TEXT)) == NULLFILE) {
/* probably too many open files */
(void) rmlock(Mailqdir,prefix);
/* continue to next message. The failure
* may be temporary */
continue;
}
(void) fgets(tmpstring,LINELEN,wfile); /* read target host */
rip(tmpstring);
if ((destaddr = mailroute(tmpstring)) == 0) {
fclose(wfile);
printf("** smtp: Unknown address %s\n",tmpstring);
(void) rmlock(Mailqdir,prefix);
continue;
}
if(target != 0 && destaddr != target){
fclose(wfile);
(void) rmlock(Mailqdir,prefix);
continue; /* Not the proper target of a kick */
}
if ((cb = lookup(destaddr)) == NULLSMTPCLI) {
/* there are enough processes running already */
if (Smtpsessions >= Smtpmaxcli) {
#ifdef SMTPTRACE
if (Smtptrace>1) {
printf("smtp daemon: too many processes\n");
}
#endif
fclose(wfile);
(void) rmlock(Mailqdir,prefix);
break;
}
if ((cb = newcb()) == NULLSMTPCLI) {
fclose(wfile);
(void) rmlock(Mailqdir,prefix);
break;
}
cb->ipdest = destaddr;
cb->destname = strdup(tmpstring);
} else {
if(cb->lock){
/* This system is already is sending mail lets not
* interfere with its send queue.
*/
fclose(wfile);
(void) rmlock(Mailqdir,prefix);
continue;
}
}
(void) fgets(from,LINELEN,wfile); /* read from */
rip(from);
if ((jp = setupjob(cb,prefix,from)) == NULLJOB) {
fclose(wfile);
(void) rmlock(Mailqdir,prefix);
del_session(cb);
break;
}
while (fgets(to,LINELEN,wfile) != NULLCHAR) {
rip(to);
if (addlist(&jp->to,to,DOMAIN) == NULLLIST) {
fclose(wfile);
del_session(cb);
}
}
fclose(wfile);
#ifdef SMTPTRACE
if (Smtptrace > 2) {
printf("queue job %s From: %s To:",prefix,from);
for (ap = jp->to; ap != NULLLIST; ap = ap->next)
printf(" %s",ap->val);
printf("\n");
}
#endif
}
/* start sending that mail */
execjobs();
/* Restart timer */
start_timer(&Smtpcli_t);
smtp_running = 0;
return;
}
/* This is the master state machine that handles a single SMTP transaction.
* It is called with a queue of jobs for a particular host.
* The logic is complicated by the "Smtpbatch" variable, which controls
* the batching of SMTP commands. If Smtpbatch is true, then many of the
* SMTP commands are sent in one swell foop before waiting for any of
* the responses. Unfortunately, this breaks many brain-damaged SMTP servers
* out there, so provisions have to be made to operate SMTP in lock-step mode.
*/
static void
smtp_send(unused,cb1,p)
int unused;
void *cb1;
void *p;
{
register struct smtpcli *cb;
register struct list *tp;
struct sockaddr_in fsocket;
char *cp;
int rcode;
int rcpts;
int goodrcpt;
int i;
int smtpbatch;
int init = 1;
#ifdef LZW
int lzwmode, lzwbits;
extern int16 Lzwbits;
extern int Lzwmode;
#endif
cb = (struct smtpcli *)cb1;
cb->lock = 1;
fsocket.sin_family = AF_INET;
fsocket.sin_addr.s_addr = cb->ipdest;
fsocket.sin_port = IPPORT_SMTP;
cb->s = socket(AF_INET,SOCK_STREAM,0);
sockmode(cb->s,SOCK_ASCII);
setflush(cb->s,-1); /* We'll explicitly flush before reading */
#ifdef SMTPTRACE
if (Smtptrace>1)
printf("SMTP client Trying...\n");
#endif
/* Set a timeout for this connection */
alarm(Smtpt4 * 1000L);
if(connect(cb->s,(char *)&fsocket,SOCKSIZE) != 0){
alarm(0L);
close_s(cb->s); /* to make sure it's closed */
if(Smtpt4 && Gateway
&& (fsocket.sin_addr.s_addr != Gateway)
#ifdef HOPPER
&& (Gateway != Ip_addr) /* g8fsl via g0mhd */
#endif
) {
/* Try it via the gateway */
fsocket.sin_addr.s_addr = Gateway;
cb->s = socket(AF_INET,SOCK_STREAM,0);
sockmode(cb->s,SOCK_ASCII);
setflush(cb->s,-1); /* We'll explicitly flush before reading */
#ifdef SMTPTRACE
if (Smtptrace>1)
printf("SMTP client Trying gateway...\n");
#endif
/* Set a timeout for this connection */
alarm(Smtpt4 * 1000L);
if(connect(cb->s,(char *)&fsocket,SOCKSIZE) != 0){
alarm(0L);
cp = sockerr(cb->s);
close_s(cb->s); /* to make sure it's closed */
#ifdef SMTPTRACE
if (Smtptrace>1)
printf("Connect failed: %s\n",cp != NULLCHAR ? cp : "");
#endif
log(cb->s,"SMTP %s Connect failed: %s",psocket(&fsocket),
cp != NULLCHAR ? cp : "");
goto quit;
}
} else {
goto quit;
}
}
alarm(0L);
#ifdef SMTPTRACE
if (Smtptrace>1)
printf("Connected\n");
#endif
#ifdef LZW
rcode = getresp(cb,200);
if(rcode == -1 || rcode >= 400)
goto quit;
if(Smtpclzw) {
char cp[LINELEN];
sendcmd(cb,"XLZW %d %d\n",Lzwbits,Lzwmode);
usflush(cb->s);
if(recvline(cb->s,cp,sizeof(cp)) == -1)
goto quit;
rip(cp);
#ifdef SMTPTRACE
if(Smtptrace>1)
printf(smtp_recv,cp);/* Display to user */
#endif
rcode = lzwmode = lzwbits = 0;
sscanf(cp,"%d %d %d",&rcode,&lzwbits,&lzwmode);
if((rcode >= 200) && (rcode < 300)) {
smtpbatch = 1;
if(lzwmode != Lzwmode || lzwbits != Lzwbits) {
lzwmode = LZWCOMPACT;
lzwbits = LZWBITS;
}
lzwinit(cb->s,lzwbits,lzwmode);
} else {
smtpbatch = Smtpbatch;
}
} else {
smtpbatch = Smtpbatch;
}
#else
smtpbatch = Smtpbatch;
if(!smtpbatch){
rcode = getresp(cb,200);
if(rcode == -1 || rcode >= 400)
goto quit;
}
#endif
/* Say HELO */
sendcmd(cb,"HELO %s\n",Hostname);
if(!smtpbatch){
rcode = getresp(cb,200);
if(rcode == -1 || rcode >= 400)
goto quit;
}
do { /* For each message... */
/* if this file open fails, skip it */
if ((cb->tfile = fopen(cb->tname,READ_TEXT)) == NULLFILE)
continue;
/* Send MAIL and RCPT commands */
sendcmd(cb,"MAIL FROM:<%s>\n",cb->jobq->from);
if(!smtpbatch){
rcode = getresp(cb,200);
if(rcode == -1 || rcode >= 400)
goto quit;
}
rcpts = 0;
goodrcpt = 0;
for (tp = cb->jobq->to; tp != NULLLIST; tp = tp->next){
sendcmd(cb,"RCPT TO:<%s>\n",tp->val);
if(!smtpbatch){
rcode = getresp(cb,200);
if(rcode == -1)
goto quit;
if(rcode < 400)
goodrcpt = 1; /* At least one good */
}
rcpts++;
}
/* Send DATA command */
sendcmd(cb,"DATA\n");
if(!smtpbatch){
rcode = getresp(cb,200);
if(rcode == -1 || rcode >= 400)
goto quit;
}
if(smtpbatch){
/* Now wait for the responses to come back. The first time
* we do this, we wait first for the start banner and
* HELO response. In any case, we wait for the response to
* the MAIL command here.
*/
#ifdef LZW
for(i= init ? 2 : 1;i > 0;i--){
#else
for(i= init ? 3 : 1;i > 0;i--){
#endif
rcode = getresp(cb,200);
if(rcode == -1 || rcode >= 400)
goto quit;
}
init = 0;
/* Now process the responses to the RCPT commands */
for(i=rcpts;i!=0;i--){
rcode = getresp(cb,200);
if(rcode == -1)
goto quit;
if(rcode < 400)
goodrcpt = 1; /* At least one good */
}
/* And finally get the response to the DATA command.
* Some servers will return failure here if no recipients
* are valid, some won't.
*/
rcode = getresp(cb,200);
if(rcode == -1 || rcode >= 400)
goto quit;
/* check for no good rcpt on the list */
if (goodrcpt == 0){
sendcmd(cb,".\n"); /* Get out of data mode */
goto quit;
}
}
/* Send the file. This also closes it */
smtpsendfile(cb);
/* Wait for the OK response */
rcode = getresp(cb,200);
if(rcode == -1)
goto quit;
if((rcode >= 200 && rcode < 300) || rcode >= 500){
/* if a good transfer or permanent failure remove job */
if (cb->errlog != NULLLIST)
retmail(cb);
/* Unlink the textfile */
(void) unlink(cb->tname);
(void) unlink(cb->wname); /* unlink workfile */
log(cb->s,"SMTP sent job %s To: %s From: %s",
cb->jobq->jobname,cb->jobq->to->val,cb->jobq->from);
}
} while(next_job(cb));
quit:
sendcmd(cb,"QUIT\n");
if (cb->errlog != NULLLIST){
retmail(cb);
(void) unlink(cb->wname); /* unlink workfile */
(void) unlink(cb->tname); /* unlink text */
}
(void) close_s(cb->s);
if(cb->tfile != NULLFILE)
fclose(cb->tfile);
cb->lock = 0;
del_session(cb);
}
/* free the message struct and data */
static void
del_session(cb)
register struct smtpcli *cb;
{
register struct smtp_job *jp,*tp;
register int i;
if (cb == NULLSMTPCLI)
return;
for(i=0; i<MAXSESSIONS; i++)
if(cli_session[i] == cb) {
cli_session[i] = NULLSMTPCLI;
break;
}
free(cb->wname);
free(cb->tname);
free(cb->destname);
for (jp = cb->jobq; jp != NULLJOB;jp = tp) {
tp = jp->next;
del_job(jp);
}
del_list(cb->errlog);
free((char *)cb);
Smtpsessions--; /* number of connections active */
}
static void
del_job(jp)
register struct smtp_job *jp;
{
if ( *jp->jobname != '\0')
(void) rmlock(Mailqdir,jp->jobname);
free(jp->from);
del_list(jp->to);
free((char *)jp);
}
/* delete a list of list structs */
void
del_list(lp)
struct list *lp;
{
register struct list *tp, *tp1;
for (tp = lp; tp != NULLLIST; tp = tp1) {
tp1 = tp->next;
free(tp->val);
free((char *)tp);
}
}
/* stub for calling mdaemon to return message to sender */
static void
retmail(cb)
struct smtpcli *cb;
{
FILE *infile;
#ifdef SMTPTRACE
if (Smtptrace > 5) {
printf("smtp job %s returned to sender\n",cb->wname);
}
#endif
if ((infile = fopen(cb->tname,READ_TEXT)) == NULLFILE)
return;
mdaemon(infile,cb->jobq->from,cb->errlog,1);
fclose(infile);
}
/* look to see if a smtp control block exists for this ipdest */
static struct smtpcli *
lookup(destaddr)
int32 destaddr;
{
register int i;
for(i=0; i<MAXSESSIONS; i++) {
if (cli_session[i] == NULLSMTPCLI)
continue;
if(cli_session[i]->ipdest == destaddr)
return cli_session[i];
}
return NULLSMTPCLI;
}
/* create a new smtp control block */
static struct smtpcli *
newcb()
{
register int i;
register struct smtpcli *cb;
for(i=0; i<MAXSESSIONS; i++) {
if(cli_session[i] == NULLSMTPCLI) {
cb = (struct smtpcli *)callocw(1,sizeof(struct smtpcli));
cb->wname = mallocw((unsigned)strlen(Mailqdir)+JOBNAME);
cb->tname = mallocw((unsigned)strlen(Mailqdir)+JOBNAME);
cli_session[i] = cb;
Smtpsessions++; /* number of connections active */
return(cb);
}
}
return NULLSMTPCLI;
}
static void
execjobs()
{
register struct smtpcli *cb;
register int i, insave, outsave;
for(i=0; i<MAXSESSIONS; i++) {
cb = cli_session[i];
if (cb == NULLSMTPCLI)
continue;
if(cb->lock)
continue;
sprintf(cb->tname,"%s/%s.txt",Mailqdir,cb->jobq->jobname);
sprintf(cb->wname,"%s/%s.wrk",Mailqdir,cb->jobq->jobname);
/* This solves the nasty hack in mailbox.c, from Mark ve3dte */
insave = Curproc->input;
outsave = Curproc->output;
Curproc->input = -1;
Curproc->output = -1;
/* Now we can call newproc with null parent sockets! */
newproc("smtp_send", 1536, smtp_send, 0, cb,NULL,0);
/* now restore parent sockets so parent can continue */
Curproc->input = insave;
Curproc->output = outsave;
#ifdef SMTPTRACE
if (Smtptrace>1)
printf("Trying Connection to %s\n",inet_ntoa(cb->ipdest));
#endif
}
}
/* add this job to control block queue */
static struct smtp_job *
setupjob(cb,id,from)
struct smtpcli *cb;
char *id,*from;
{
register struct smtp_job *p1,*p2;
p1 = (struct smtp_job *)callocw(1,sizeof(struct smtp_job));
p1->from = strdup(from);
strcpy(p1->jobname,id);
/* now add to end of jobq */
if ((p2 = cb->jobq) == NULLJOB)
cb->jobq = p1;
else {
while(p2->next != NULLJOB)
p2 = p2->next;
p2->next = p1;
}
return p1;
}
/* called to advance to the next job */
static int
next_job(cb)
register struct smtpcli *cb;
{
register struct smtp_job *jp;
jp = cb->jobq->next;
del_job(cb->jobq);
/* remove the error log of previous message */
del_list(cb->errlog);
cb->errlog = NULLLIST;
cb->jobq = jp;
if (jp == NULLJOB)
return 0;
sprintf(cb->tname,"%s/%s.txt",Mailqdir,jp->jobname);
sprintf(cb->wname,"%s/%s.wrk",Mailqdir,jp->jobname);
#ifdef SMTPTRACE
if (Smtptrace > 5) {
printf("sending job %s\n",jp->jobname);
}
#endif
return 1;
}
/* Mail routing function. */
int32
mailroute(dest)
char *dest;
{
int32 destaddr = 0L;
#ifdef HOPPER
struct route *rp;
#endif
#ifdef SMTPTRACE
if (Smtptrace > 6)
printf("Route lookup for = %s\n",dest);
#endif
#ifdef HOPPER
if (*dest == '\0'){
#ifdef SMTPTRACE
if (Smtptrace > 6)
printf("Local mail\n");
#endif
return Ip_addr;
}
#endif
/* look up address or use the gateway */
if(UseMX){
destaddr = resolve_mx(dest);
#ifdef SMTPTRACE
if (Smtptrace > 6)
printf("MX lookup returned = %s\n",inet_ntoa(destaddr));
#endif
}
if(destaddr == 0L)
if((destaddr = resolve(dest)) == 0L)
if (Gateway != 0L)
destaddr = Gateway; /* Use the gateway */
#ifdef SMTPTRACE
if (Smtptrace > 6)
printf("Address resolver returned = %s\n",inet_ntoa(destaddr));
#endif
#ifdef HOPPER
if (UseHopper && (destaddr != Ip_addr)) {
if ((rp=rt_lookup(destaddr)) != NULLROUTE)
if (rp->gateway != 0L)
destaddr=rp->gateway;
#ifdef SMTPTRACE
if (Smtptrace > 6)
printf("Hopper returned = %s\n",inet_ntoa(destaddr));
#endif
}
#endif
#ifdef SMTPTRACE
if (Smtptrace > 6)
printf("Mailroute returned = %s\n",inet_ntoa(destaddr));
#endif
return destaddr;
}
/* save line in error list */
static void
logerr(cb,line)
struct smtpcli *cb;
char *line;
{
register struct list *lp,*tp;
tp = (struct list *)callocw(1,sizeof(struct list));
tp->val = strdup(line);
/* find end of list */
if ((lp = cb->errlog) == NULLLIST)
cb->errlog = tp;
else {
while(lp->next != NULLLIST)
lp = lp->next;
lp->next = tp;
}
}
static int
smtpsendfile(cb)
register struct smtpcli *cb;
{
int error = 0;
strcpy(cb->buf,"\n");
while(fgets(cb->buf,sizeof(cb->buf),cb->tfile) != NULLCHAR) {
/* Escape a single '.' character at the beginning of a line */
if(strcmp(cb->buf,".\n") == 0)
usputc(cb->s,'.');
usputs(cb->s,cb->buf);
}
fclose(cb->tfile);
cb->tfile = NULLFILE;
/* Send the end-of-message command */
if(cb->buf[strlen(cb->buf)-1] == '\n')
sendcmd(cb,".\n");
else
sendcmd(cb,"\n.\n");
return error;
}
/* do a printf() on the socket with optional local tracing */
#ifdef ANSIPROTO
static void
sendcmd(struct smtpcli *cb,char *fmt, ...)
{
va_list args;
va_start(args,fmt);
#ifdef SMTPTRACE
if(Smtptrace>1){
printf("smtp sent: ");
vprintf(fmt,args);
}
#endif
vsprintf(cb->buf,fmt,args);
usputs(cb->s,cb->buf);
va_end(args);
}
#else
static void
sendcmd(cb,fmt,arg1,arg2,arg3,arg4)
struct smtpcli *cb;
char *fmt;
int arg1,arg2,arg3,arg4;
{
#ifdef SMTPTRACE
if(Smtptrace>1){
printf("smtp sent: ");
printf(fmt,arg1,arg2,arg3,arg4);
}
#endif
sprintf(cb->buf,fmt,arg1,arg2,arg3,arg4);
usputs(cb->s,cb->buf);
}
#endif
/* Wait for, read and display response from server. Return the result code. */
static int
getresp(cb,mincode)
struct smtpcli *cb;
int mincode; /* Keep reading until at least this code comes back */
{
int rval;
char line[LINELEN];
usflush(cb->s);
for(;;){
/* Get line */
if(recvline(cb->s,line,LINELEN) == -1){
rval = -1;
break;
}
rip(line); /* Remove cr/lf */
rval = atoi(line);
#ifdef SMTPTRACE
if(Smtptrace>1)
printf(smtp_recv,line);/* Display to user */
#endif
if(rval >= 500) { /* Save permanent error replies */
char tmp[LINELEN];
if(cb->errlog == NULLLIST) {
sprintf(tmp,"While talking to %s:",
cb->destname);
logerr(cb,tmp);
}
if(cb->buf[0] != '\0') { /* Save offending command */
rip(cb->buf);
sprintf(tmp,">>> %s",cb->buf);
logerr(cb,tmp);
cb->buf[0] = '\0';
}
sprintf(tmp,"<<< %s",line);
logerr(cb,tmp); /* save the error reply */
}
/* Messages with dashes are continued */
if(line[3] != '-' && rval >= mincode)
break;
}
return rval;
}